﻿using System;
using System.Collections.Generic;
using RayDen.Library.Components.SystemComponents;
using RayDen.RayEngine.Core;
using RayDen.RayEngine.Core.Interface;
using RayDen.RayEngine.Core.Types;
using RayDen.RayEngine.Managers;
using RayDen.RayEngine.Samplers;

namespace RayDen.RayEngine.Engines.ProgressivePhotonMapping
{
    public class PPMDeviceRenderThread : DeviceRenderThreadBase
    {
        protected int ID
        {
            get { return this.threadIndex; }
        }
        protected internal PPMContext context;
        protected PPMDeviceRenderThread(int index, RayEngineScene scene)
            : base(index, scene)
        {
        }

        public PPMDeviceRenderThread(int index, IIntersectionEngine device, RayEngineScene scn, bool lowLatency, IImageFilm pixelDevice, ISampler sampler, SurfaceSampler ss, PPMContext ctx, IFrameManager frameManager)
            : base(index, scn)
        {
            this.context = ctx;
            Init(device, lowLatency, pixelDevice, sampler, ss);
        }

        protected override PathBufferBase CreatePathBuffer(int maxPath, IRayEngineScene scene, IImageFilm pixelDevice, ISampler sampler, SurfaceSampler ss)
        {
            var pathBuffer = new  PPMPathBuffer(context);
            pathBuffer.Init(maxPath, (RayEngineScene)scene, pixelDevice, new SamplingContext() { SurfaceSampler = ss, PrimarySpaceSampler = sampler, LightSampler = new LightSampler((RayEngineScene)scene)});
            return pathBuffer;
        }

        protected override void ThreadJob(System.Threading.CancellationToken t, DeviceRenderThreadBase rt)
        {
            var deviceRenderThread = (PPMDeviceRenderThread)rt;
            Tracer.TraceLine("CL Render Thread {0} started", deviceRenderThread.threadIndex);

#if VERBOSE
            try {
#endif
            var todoBuffers = new Queue<RayBuffer>();
            for (var i = 0; i < DeviceRenderBufferCount; i++)
                todoBuffers.Enqueue(deviceRenderThread.rayBuffers[i]);
            bool eyesSplated = false;

            while (!t.IsCancellationRequested)
            {
                while (todoBuffers.Count > 0)
                {
                    var rayBuffer = todoBuffers.Dequeue();
                    rayBuffer.Reset();
                    deviceRenderThread._pathRayProcessors[0].FillRayBuffer(rayBuffer);
                    deviceRenderThread.intersectionDevice.PushRayBuffer(rayBuffer, deviceRenderThread.threadIndex);
                }
                var rayBuff = deviceRenderThread.intersectionDevice.PopRayBuffer(deviceRenderThread.threadIndex);
                if (rayBuff != null && rayBuff.UserData == deviceRenderThread.threadIndex)
                {
                    deviceRenderThread._pathRayProcessors[0].AdvancePaths(rayBuff);
                    todoBuffers.Enqueue(rayBuff);
                }

                if (deviceRenderThread.ID == 0 )
                {
                    if (context.Splat)
                    {
#if VERBOSE
                        Tracer.TraceLine("Splat photon contribution points");
#endif

                        (deviceRenderThread.pixelDevice as ImageFilmBase).SplatHitPoints(
                            deviceRenderThread.context.Grid.GetHitPoints(), deviceRenderThread.context);
                        deviceRenderThread.context.ResetContext();
                        eyesSplated = false;
                    }

                   
                else if (context.HitPointsGathered && !eyesSplated)
                {
#if VERBOSE
                    Tracer.TraceLine("Splat eye points");
#endif
                    (deviceRenderThread.pixelDevice as ImageFilmBase).SplatHitPoints(
                        deviceRenderThread.context.hitPoints, deviceRenderThread.context);
                    eyesSplated = true;
                }

                }
                
            }
#if VERBOSE
            }
            catch (Exception ex) {
                Tracer.TraceLine("Exiting rendering : Reason \n\r{0}", ex);
            }
#endif
            Tracer.TraceLine("CL Render Thread {0} exited", deviceRenderThread.threadIndex);
        }
    }
}